#include "../include/SocketIO.h"

#include "../include/my_header.h"
#include <iostream>
using std::cout;
using std::endl;

namespace wd
{

int SocketIO::recvPeek(char * buff, int len) const
{
    int ret = -1;
    do{
        ret = recv(_fd, buff, len, MSG_PEEK);
    }while(ret == -1 && errno == EINTR); 
    return ret;
}

    
int SocketIO::sendn(const char * buff, int len) const
{
    const char * pbuf = buff;
    int left = len;
    while(left > 0) {
        int ret = send(_fd, pbuf, left, 0);
        if(ret < 0) {
            perror("send");
            return ret;
        }

        left -= ret;
        pbuf += ret;
    }
    return len;
}


int SocketIO::readn(char * buff, int len) const
{
    char * pbuf = buff;
    int left = len;
    while(left > 0) {
        int ret = recv(_fd, pbuf, left, 0);
        if(ret == -1 && errno == EINTR)
            continue;
        else if(ret == -1) {
            perror("recv");
            return ret;
        }

        left -= ret;
        pbuf += ret;
    }
    return len;
}

//char buff[1024] = {0};
//maxlen: 1024
int SocketIO::readline(char * buff, int maxlen) const
{
    //将buff的最后一个位置的元素设置为'\0'
    //防止出现数据越界的情况
    int left = maxlen - 1;///
    char * pbuf = buff;
    int total = 0;
    while(left > 0) {
        //没有移走内核接收缓冲区中的数据
        int ret = recvPeek(pbuf, left);
        
        //查看这ret个字节中是否有'\n'
        for(int i = 0; i < ret; ++i) {
            //发现了\n
            if(pbuf[i] == '\n') {
                int sz = i + 1;
                ret = readn(pbuf, sz);
                total += ret;
                return total;
            }
        }
        //移走内核接收缓冲区中的数据
        ret = readn(pbuf, ret);
        //没有发现\n
        left -= ret;
        pbuf += ret;
        total += ret;
    }
    buff[maxlen - 1] = '\0';
    return maxlen - 1;
}
int SocketIO::readPacket(Packet& packet) {
    // 步骤1：读取 TLV 头部（4字节 type + 4字节 length，共8字节）
    char tlvHeader[8] = {0};
    int headerRet = readn(tlvHeader, 8);  // 用 readn 确保读取完整8字节
    if (headerRet != 8) {
        cout << "[SocketIO::readPacket] 读取 TLV 头部失败，实际读 " << headerRet << " 字节" << endl;
        return -1;  // 返回-1表示失败
    }

    // 步骤2：解析头部（网络字节序 → 主机字节序）
    int tlvType_net, tlvLength_net;
    memcpy(&tlvType_net, tlvHeader, 4);    // 提取 type（网络字节序）
    memcpy(&tlvLength_net, tlvHeader + 4, 4);  // 提取 length（网络字节序）

    int tlvType_host = ntohl(tlvType_net);    // 转主机字节序
    int tlvLength_host = ntohl(tlvLength_net);  // 转主机字节序

    // 步骤3：校验 length 合法性（避免恶意数据或溢出）
    if (tlvLength_host < 0 || tlvLength_host > 1024) {  // 与 TLV 的 DATA_MAX_SIZE 一致
        cout << "[SocketIO::readPacket] 无效 TLV 数据长度：" << tlvLength_host << " 字节" << endl;
        return -1;
    }

    // 步骤4：读取 TLV 数据部分（length 字节）
    char tlvData[1024] = {0};  // 缓冲区大小与 DATA_MAX_SIZE 一致
    int dataRet = readn(tlvData, tlvLength_host);  // 确保读取完整数据
    if (dataRet != tlvLength_host) {
        cout << "[SocketIO::readPacket] 读取 TLV 数据失败，实际读 " << dataRet << " 字节" << endl;
        return -1;
    }

    // 步骤5：将解析结果赋值给 Packet 对象
    packet._type = tlvType_host;          // 赋值 type
    packet._length = tlvLength_host;      // 赋值 length
    packet._msg = string(tlvData, tlvLength_host);  // 赋值实际字符串数据

    return 0;  // 返回0表示成功
}
}//end of namespace wd
